﻿using System;
using System.Linq;
using CCodeTreeLib;
using SqlOrm.Xml;

namespace SqlOrm.TreeBuilders
{
    public class DataContractTreeBuilder : CCodeTree
    {
        DataDictionary _ddl;

        public DataContractTreeBuilder(DataDictionary ddl)
        {
            _ddl = ddl;
            BuildDataContracts();
        }

        private void BuildDataContracts()
        {
            Console.WriteLine("Building entities...");
            Usings.Add(new CCodeUsing("System"));
            Usings.Add(new CCodeUsing("System.Runtime.Serialization"));
            var ns = AddStatement(new CCodeNamespace(_ddl.Settings.DataContractOutput.clrnamespace));
            foreach (var table in _ddl.Definition.Schema.Table.Where(x => !x.exclude))
            {
                var enumFields = table.Field.Where(x => !string.IsNullOrEmpty(x.EnumName));
                foreach (var f in enumFields)
                {
                    var cEnum = new CCodeEnum(string.Format("{0}{1}", table.name, f.title));
                    foreach (var e in f.Enum)
                    {
                        if (!string.IsNullOrEmpty(e.value))
                        {
                            int val;
                            if (int.TryParse(e.value, out val))
                                cEnum.Values.Add(new CCodeAssign(e.desc, val.ToString()));
                            else cEnum.Values.Add(new CCodeAssign(e.desc, null));
                        }
                    }
                    Console.WriteLine("Enum: " + cEnum.Name);
                    ns.AddStatement(cEnum);
                }
            }
            foreach (var table in _ddl.Definition.Schema.Table.Where(x => !x.exclude))
            {
                var cls = new CCodeClass(table.ClassName);
                cls.Modifier = Modifier.Public;
                cls.Attributes.Add(new CCodeAttribute("DataContract", string.Format("Namespace = \"{0}\", Name = \"{1}\"", _ddl.Settings.DataContractOutput.urinamespace, table.name)));
                foreach (var f in table.Field)
                {
                    var prop = new CCodeProperty(!string.IsNullOrEmpty(f.title) ? f.title : f.name, f.ClrDataType);
                    prop.Attributes.Add(new CCodeAttribute("DataMember", string.Format( "Name = \"{0}\", IsRequired = true, Order = {1}",prop.Name,Array.IndexOf(table.Field.ToArray(),f)) ));
                    cls.AddStatement(prop);
                }
                Console.WriteLine("Entity: " + cls.Name);
                ns.AddStatement(cls);
            }
            if (_ddl.Definition.Procedures!=null)
            {
                foreach (var proc in _ddl.Definition.Procedures)
                {
                    if (proc.Output != null && proc.NestedFields.Count > 0)
                    {
                        var cls = new CCodeClass(proc.name + "Output");
                        cls.Modifier = Modifier.Public;
                        cls.Attributes.Add(new CCodeAttribute("DataContract", string.Format("Namespace = \"{0}\", Name = \"{1}\"", _ddl.Settings.DataContractOutput.urinamespace, proc.name)));
                        foreach (var f in proc.NestedFields.Where(x => x.NestedClassName == null).Select(x => x.Field))
                        {
                            cls.AddStatement(new CCodeProperty(!string.IsNullOrEmpty(f.title) ? f.title : f.name, f.ClrDataType));
                        }
                        Console.WriteLine("Entity: " + cls.Name);
                        ns.AddStatement(cls);
                    }
                }
            }
        }
    }
}
